/*
 *  objects-object.h
 *  joosVM
 *
 *  Created by Smári Waage on 14.8.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */

#ifndef objects_object___ 
#define objects_object___ 

#include "objects-root.h"
/*
 * HeapObject is a internal base class for all pointer objects,
 * +------------------------+
 * |	TypeInfo/fwAddr		| //Holds Internal typeInfo, but when the obj has been relocated in gc then fwAddress is written in the field.
 * +------------------------+ a pseudo oo jvm written in c++ n :-)
 */
class HeapObject : public Pointer {
	
	//What is true for HeapObject, that is all objects.
	//HeapObject is never initialized by it self, so it is an abstract class.
	//Then for all objects it is true that...
	//Type is set, it has an object tag, 
	
public:
	static const int kLocalOffset = 0;
	static const int kfwAddress  = kLocalOffset;
	static const int kInternalTypeOffset = kfwAddress + kPointerSize;
	static const int kHeaderSize =  kInternalTypeOffset + kPointerSize;	
	
	inline HeapObject* address() { 
		REQUIRE(isHeapObject() && Heap::isAddressOk(this))
		return (HeapObject*)(this - heap_object_tag); 
	}
	static HeapObject* fromPointer(HeapObject* value) { 
		//value is just a void pointer, so it needs to fit the size.
		REQUIRE(sizeof(value) == 4)
		HeapObject* tmp = value + heap_object_tag; 
		ENSURE(tmp->isHeapObject())
		return tmp;
	}
	static HeapObject* allocHeapObject(unsigned int length){
		//we cant be allocating nothing.
		REQUIRE(length > 0 && length % 4 == 0)
		
		void* p = Heap::allocObject(length);
		HeapObject* hp = fromPointer((HeapObject*)p);
		dout(debug_heap,"pointer %p heapP: %p \n",p,hp)
		//fromPointer makes sure that we have an object
		return hp;
	}
	
	Smi* getInternalType(){
		return (Smi*)field(kInternalTypeOffset);
	}
	void setInternalType(Smi* type){
		setField(kInternalTypeOffset, type);
	}
	
	int size();
	Pointer* forward(Pointer** nHP);
	void scan(Pointer** nHP);
	
protected:
	//address makes sure that this is an object
	inline Pointer** fieldAddrAt(int index) {return (Pointer**) (address() + index); }
	// Field getter
	inline Pointer* field(int index) {
		REQUIRE(isHeapObject())
		return *fieldAddrAt(index);
	}
	
	// Field setter
	inline void setField(int index, Pointer* value) {
		REQUIRE(isHeapObject() && (index == 4 || size() >index))
		*fieldAddrAt(index) = value;
		ENSURE(field(index) == value)
	}
	
	
};


class HeapPrimitive : public HeapObject{
public:
	static const int kValueOffset = HeapObject::kHeaderSize;
	static const int kHeaderSize = kValueOffset + kPointerSize;
	
	static HeapPrimitive* Initialize(u4 value){
		HeapPrimitive* p = (HeapPrimitive*)HeapObject::allocHeapObject(HeapPrimitive::kHeaderSize);
		p->setInternalType(Smi::fromInt(IType_HeapPrimitive));
		p->setValue(value);
		return p;
	}
	u4 getValue(){
		return (u4)field(kValueOffset);
	}
	void setValue(u4 value){
		setField(kValueOffset, (Pointer*)value);
	}
	
	int heapprimitive_size(){
		return HeapPrimitive::kHeaderSize;
	}
	void heapprimitive_scan(Pointer** nHP){
		return;
	}
};
class HeapDblPrimitive : public HeapObject{
public:
	static const int kValueOffset = HeapObject::kHeaderSize;
	static const int kHeaderSize = kValueOffset + kDoubleSize;
	
	static HeapDblPrimitive* Initialize(u8 value){
		HeapDblPrimitive* p = (HeapDblPrimitive*)HeapObject::allocHeapObject(HeapDblPrimitive::kHeaderSize);
		p->setInternalType(Smi::fromInt(IType_HeapDblPrimitive));
		p->setValue(value);
		return p;
	}
	u8 getValue(){
		return *(u8*)(address() +kValueOffset);//   field(kValueOffset);
	}
	void setValue(u8 value){
		*(u8*)(address() +kValueOffset) = value; //setField(kValueOffset, value);
	}
	int heapdblprimitive_size(){
		return HeapDblPrimitive::kHeaderSize;
	}
	void heapdblprimitive_scan(Pointer** nHP){
		return;
	}
};

	
#endif
	
